/*
-----------------------------------------------------------------------------
This source file is part of the
   ___                 __    __ _ _    _ 
  /___\__ _ _ __ ___  / / /\ \ (_) | _(_)
 //  // _` | '__/ _ \ \ \/  \/ / | |/ / |
/ \_// (_| | | |  __/  \  /\  /| |   <| |
\___/ \__, |_|  \___|   \/  \/ |_|_|\_\_|
      |___/                              
      Tutorial Framework
      http://www.ogre3d.org/tikiwiki/
-----------------------------------------------------------------------------
*/
#include "GameApp.h"
#include "CollisionDetection.h"
#include <OgreStringConverter.h>

//-------------------------------------------------------------------------------------
CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonID)
{
    switch (buttonID)
    {
    case OIS::MB_Left:
        return CEGUI::LeftButton;
 
    case OIS::MB_Right:
        return CEGUI::RightButton;
 
    case OIS::MB_Middle:
        return CEGUI::MiddleButton;
 
    default:
        return CEGUI::LeftButton;
    }
}
//-------------------------------------------------------------------------------------
GameApp::GameApp(void)
{
}
//-------------------------------------------------------------------------------------
GameApp::~GameApp(void)
{
}
//-------------------------------------------------------------------------------------
void GameApp::createScene(void)
{
	// Set the ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
//-------------------------------------------------------------------------------------	
	// Simple Skybox
	mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox");
	guesses = 10;
	active = false;

/*------
* Camera
-------*/
	//Debug Camera settings
	//mCamera->setPosition(0, 100, 300);	// better debug camera angle IMO - Carl.
	//mCamera->lookAt(0, 30, 0);
	//mCamera->getDirection();
	
	mCamera->setPosition(0, 30, 0);
	mCamera->lookAt(0, 30, 0);
	mCamera->getDirection();
//-------------------------------------------------------------------------------------
#pragma region Torch

	torch = mSceneMgr->createLight("Torch");
	torch->setType(Ogre::Light::LT_SPOTLIGHT);
	torch->setDiffuseColour(0.0, 1.0, 0);
	torch->setSpecularColour(0.0, 0.5, 0);
	torch->setDirection(mCamera->getDirection());
	torch->setPosition(mCamera->getPosition());
	torch->setSpotlightRange(Ogre::Degree(20), Ogre::Degree(60));
	torch->setVisible(false);
	/*	Attenuation:
	*	Range - distance before light has no effect on objects
	*	Constant - 0.0 increase brightness, >0.0 descrease brightness
	*	Linear - >0.0 light fades faster over distance (straight line)
	*	Quadratic - >0.0 light fades faster over distance (angle from source)
	*
	*	att = const + lin * dist + quad * dist^2
	*	----------------------------------------
	*	Need to be up close to a shape for full luminosity of torch
	*	Remove line below to have infinite luminosity
	*/
	torch->setAttenuation(200, 1.0, 0.022, 0.0019);

#pragma endregion Torch
//-------------------------------------------------------------------------------------
#pragma region Player

	player		= mSceneMgr->createEntity("Player", "HideAndSeekPlayer.mesh");
	mCamNode	= mSceneMgr->getRootSceneNode()->createChildSceneNode("CameraNode");
	playerNode	= mCamNode->createChildSceneNode("PlayerNode");

	mCamNode->attachObject(mCamera);
	playerNode->attachObject(player);
	playerNode->attachObject(torch);
	
	playerNode->setPosition(0, 6, 0); // Y value set to 6 so player isn't immediately colliding with the floor!
	
	// Debug purposes
	playerNode->showBoundingBox(true);

#pragma endregion Player
//-------------------------------------------------------------------------------------
#pragma region Shapes
/*
*	All the shapes are confined to the following boundaries:
*	X: +180 to -180
*	Y: 0 to -300
*	Z: +180 to -180
*/
	srand((unsigned)time(NULL));
	hiddenInt = rand() % NUMPLANES;

#pragma region Offsets
/*
*  Cubes
*/
	Ogre::Vector3 cubeOffset[9];
	cubeOffset[0] = Ogre::Vector3(70.0f,	0.0f,	10.0f);
	cubeOffset[1] = Ogre::Vector3(10.0f,	0.0f,	100.0f);
	cubeOffset[2] = Ogre::Vector3(-180.0f,	0.0f,	180.0f);
	cubeOffset[3] = Ogre::Vector3(180.0f,	0.0f,	180.0f);
	cubeOffset[4] = Ogre::Vector3(-97.0f,	0.0f,	-102.0f);
	cubeOffset[5] = Ogre::Vector3(130.0f,	0.0f,	-53.0f);
	cubeOffset[6] = Ogre::Vector3(152.0f,	0.0f,	-173.0f);
	cubeOffset[7] = Ogre::Vector3(146.0f,	0.0f,	20.0f);
	cubeOffset[8] = Ogre::Vector3(35.0f,	0.0f,	-100.0f);
/*
*  Spheres
*/
	Ogre::Vector3 sphereOffset[9];
	sphereOffset[0] = Ogre::Vector3(10.0f,	-100.0f,	10.0f);
	sphereOffset[1] = Ogre::Vector3(73.0f,	-100.0f,	-161.0f);
	sphereOffset[2] = Ogre::Vector3(13.0f,	-100.0f,	-147.0f);
	sphereOffset[3] = Ogre::Vector3(-121.0f,-100.0f,	36.0f);
	sphereOffset[4] = Ogre::Vector3(-150.0f,-100.0f,	-122.0f);
	sphereOffset[5] = Ogre::Vector3(-173.0f,-100.0f,	1.0f);
	sphereOffset[6] = Ogre::Vector3(69.0f,	-100.0f,	69.0f);
	sphereOffset[7] = Ogre::Vector3(173.0f,	-100.0f,	15.0f);
	sphereOffset[8] = Ogre::Vector3(29.0f,	-100.0f,	180.0f);
/*
*  Tetra
*/
	Ogre::Vector3 tetraOffset[9];
	tetraOffset[0] = Ogre::Vector3(10.0f,	-200.0f,	10.0f);
	tetraOffset[1] = Ogre::Vector3(32.0f,	-200.0f,	-159.0f);
	tetraOffset[2] = Ogre::Vector3(169.0f,	-200.0f,	-25.0f);
	tetraOffset[3] = Ogre::Vector3(111.0f,	-200.0f,	159.0f);
	tetraOffset[4] = Ogre::Vector3(-100.0f,	-200.0f,	9.0f);
	tetraOffset[5] = Ogre::Vector3(-177.0f,	-200.0f,	177.0f);
	tetraOffset[6] = Ogre::Vector3(-150.0f,	-200.0f,	-68.0f);
	tetraOffset[7] = Ogre::Vector3(-40.0f,	-200.0f,	125.0f);
	tetraOffset[8] = Ogre::Vector3(88.0f,	-200.0f,	60.0f);
/*
*  Tube
*/

	Ogre::Vector3 tubeOffset[9];
	tubeOffset[0] = Ogre::Vector3(10.0f,	-300.0f,	10.0f);
	tubeOffset[1] = Ogre::Vector3(-101.0f,	-300.0f,	162.0f);
	tubeOffset[2] = Ogre::Vector3(40.0f,	-300.0f,	154.0f);
	tubeOffset[3] = Ogre::Vector3(-30.0f,	-300.0f,	99.0f);
	tubeOffset[4] = Ogre::Vector3(127.0f,	-300.0f,	44.0f);
	tubeOffset[5] = Ogre::Vector3(136.0f,	-300.0f,	-121.0f);
	tubeOffset[6] = Ogre::Vector3(-149.0f,	-300.0f,	-139.0f);
	tubeOffset[7] = Ogre::Vector3(-15.0f,	-300.0f,	-166.0f);
	tubeOffset[8] = Ogre::Vector3(180.0f,	-300.0f,	-170.0f);

/*
*  Hidden Shape
*/
	Ogre::Vector3 hiddenOffset[4];
	hiddenOffset[0]	= Ogre::Vector3(rand() % 180,	  0.0, rand() % 180);
	hiddenOffset[1]	= Ogre::Vector3(rand() % 180, -100.0f, rand() % 180);
	hiddenOffset[2]	= Ogre::Vector3(rand() % 180, -200.0f, rand() % 180);
	hiddenOffset[3]	= Ogre::Vector3(rand() % 180, -300.0f, rand() % 180);

#pragma endregion Offsets
//-------------------------------------------------------------------------------------
#pragma region SwitchHiddenShape

	switch(hiddenInt)
	{
	case 0:
		hiddenShape = mSceneMgr->createEntity("HiddenShape"+Ogre::StringConverter::toString(1), "HideAndSeekBox.mesh");
		hiddenShape->setMaterialName("HideAndSeekShader/Cube");
		hiddenNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HiddenNode"+Ogre::StringConverter::toString(1), hiddenOffset[0]);
		hiddenShape->setVisible(true);
		hiddenNode->attachObject(hiddenShape);
		break;
	case 1:
		hiddenShape = mSceneMgr->createEntity("HiddenShape"+Ogre::StringConverter::toString(2), "HideAndSeekSphere.mesh");
		hiddenShape->setMaterialName("HideAndSeekShader/Sphere");
		hiddenNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HiddenNode"+Ogre::StringConverter::toString(2), hiddenOffset[1]);
		hiddenShape->setVisible(true);
		hiddenNode->attachObject(hiddenShape);
		break;
	case 2:
		hiddenShape = mSceneMgr->createEntity("HiddenShape"+Ogre::StringConverter::toString(3), "HideAndSeekTetra.mesh");
		hiddenShape->setMaterialName("HideAndSeekShader/Tetra");
		hiddenNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HiddenNode"+Ogre::StringConverter::toString(3), hiddenOffset[2]);
		hiddenShape->setVisible(true);
		hiddenNode->attachObject(hiddenShape);
		break;
	case 3:
		hiddenShape = mSceneMgr->createEntity("HiddenShape"+Ogre::StringConverter::toString(4), "HideAndSeekTube.mesh");
		hiddenShape->setMaterialName("HideAndSeekShader/Barrel");
		hiddenNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HiddenNode"+Ogre::StringConverter::toString(4), hiddenOffset[3]);
		hiddenShape->setVisible(true);
		hiddenNode->attachObject(hiddenShape);
		break;
	}

#pragma endregion SwitchHiddenShape
//-------------------------------------------------------------------------------------
#pragma region Planes

	int i = 0;
	for(int j = -5.0f; i < NUMPLANES; j -= 100.0f)
	{
		planes[i] = mSceneMgr->createEntity("Plane" + Ogre::StringConverter::toString(i+1), "HideAndSeekPlane.mesh");
		planes[i]->setMaterialName("HideAndSeekShader/Glass");
		planeNode[i] =	// Set each planes positions
		mSceneMgr->getRootSceneNode()->createChildSceneNode("Plane" + Ogre::StringConverter::toString(i+1) + "Node",
															Ogre::Vector3(0.0f, j, 0.0f));
		planeNode[i]->showBoundingBox(true);
		planeNode[i]->attachObject(planes[i]);
		
		i++;
	}

#pragma endregion Planes

#pragma region Platforms

	int plat	= 0;
	int upPlat	= 4;
	int downPlat= 7;
	int upY		= -105.0f;
	int downY	= -5.0f;
	for(int y = -5.0f; plat < NUM_PLATS; y -= 100.0f)
	{

		platform[plat] = mSceneMgr->createEntity("Platform" + Ogre::StringConverter::toString(plat+1), "HideAndSeekPlat.mesh");
		platform[plat]->setMaterialName("HideAndSeekShader/Glass");

		arrowPlat[plat] = mSceneMgr->createEntity("ArrowPlat" + Ogre::StringConverter::toString(plat+1), "HideAndSeekPlat.mesh");
		
		if(plat < upPlat)
		{
			platNode[plat] =
				mSceneMgr->getRootSceneNode()->createChildSceneNode("Plat" + Ogre::StringConverter::toString(plat+1) + "Node",
																Ogre::Vector3(0.0f, y, 286.0f));

			arrowPlatNode[plat] = 
				mSceneMgr->getRootSceneNode()->createChildSceneNode("Arrow" + Ogre::StringConverter::toString(plat+1), 
																Ogre::Vector3(0.0f, y, 286.0f));
			arrowPlatNode[plat]->pitch(Ogre::Radian(Ogre::Degree(90)));
			arrowPlatNode[plat]->translate(0,55,50);
			arrowPlat[plat]->setMaterialName("HideAndSeekShader/Glass");
			

		}
		else if((plat >= upPlat) && (plat < downPlat))
		{
			platNode[plat] =
				mSceneMgr->getRootSceneNode()->createChildSceneNode("Plat" + Ogre::StringConverter::toString(plat+1) + "Node",
																Ogre::Vector3(182, upY, -275.0f));

			arrowPlatNode[plat] = 
				mSceneMgr->getRootSceneNode()->createChildSceneNode("Arrow" + Ogre::StringConverter::toString(plat+1), 
																Ogre::Vector3(182.0f, upY, -275.0f));
			arrowPlatNode[plat]->pitch(Ogre::Radian(Ogre::Degree(90)));
			arrowPlatNode[plat]->translate(0,55,-50);
			arrowPlat[plat]->setMaterialName("HideAndSeekShader/UpArrow");

			upPlat++;
			upY -= 100.0f;
		}
		else if(plat >= downPlat)
		{
			platNode[plat] =
				mSceneMgr->getRootSceneNode()->createChildSceneNode("Plat" + Ogre::StringConverter::toString(plat+1) + "Node",
																Ogre::Vector3(-175.0f, downY, -275.0f));

			arrowPlatNode[plat] = 
				mSceneMgr->getRootSceneNode()->createChildSceneNode("Arrow" + Ogre::StringConverter::toString(plat+1), 
																Ogre::Vector3(-175.0f, downY, -275.0f));
			arrowPlatNode[plat]->pitch(Ogre::Radian(Ogre::Degree(90)));
			arrowPlatNode[plat]->translate(0,55,-50);
			arrowPlat[plat]->setMaterialName("HideAndSeekShader/DownArrow");

			downPlat++;
			downY -=100.0f;
		}

		platNode[plat]->showBoundingBox(true);
		platNode[plat]->attachObject(platform[plat]);
		
		platCube[plat] = mSceneMgr->createEntity("PlatAABB" + Ogre::StringConverter::toString(plat+1), "HideAndSeekBox.mesh");
		platCubeNode[plat] = platNode[plat]->createChildSceneNode("PlatAABB" + Ogre::StringConverter::toString(plat+1) + "Node");
		platCube[plat]->setVisible(false);
		platCubeNode[plat]->attachObject(platCube[plat]);
				
		arrowPlatNode[plat]->attachObject(arrowPlat[plat]);
		arrowPlatNode[plat]->showBoundingBox(true);


		plat++;
	}

#pragma endregion Platforms
//-------------------------------------------------------------------------------------
#pragma region Cubes

	for(int i = 0; i < NUMSHAPES; i++)
	{
		tempCubes[i] = mSceneMgr->createEntity("Cube"+Ogre::StringConverter::toString(i+1), "HideAndSeekBox.mesh");
		tempCubes[i]->setMaterialName("HideAndSeekShader/Cube");
		cubeNodes[i] = mSceneMgr->getRootSceneNode()->createChildSceneNode("Cube"+Ogre::StringConverter::toString(i+1)+"Node", cubeOffset[i]);
		tempCubes[i]->setVisible(false);
		cubeNodes[i]->attachObject(tempCubes[i]);
	}

	int rndInt = (rand() % NUMSHAPES) + 1;
	maxInt = rndInt;
	cubeInt = rndInt;

	for(int i = 0; i < rndInt; i++)
	{
		bool visible = false;
		do
		{
			int rndPos = rand() % NUMSHAPES;

			if (tempCubes[rndPos]->getVisible() == false)
			{
				tempCubes[rndPos]->setVisible(true);
				visible = true;
				cubes[i] = tempCubes[rndPos];
			}
		} while (visible == false);
	}

	// Get number of total shapes so far
	totalShapes = rndInt;

#pragma endregion Cubes
//-------------------------------------------------------------------------------------
#pragma region Spheres

	for(int i = 0; i < NUMSHAPES; i++)
	{
		tempSpheres[i] = mSceneMgr->createEntity("Sphere"+Ogre::StringConverter::toString(i+1), "HideAndSeekSphere.mesh");
		tempSpheres[i]->setMaterialName("HideAndSeekShader/Sphere");
		sphereNodes[i] = mSceneMgr->getRootSceneNode()->createChildSceneNode("Sphere"+Ogre::StringConverter::toString(i+1)+"Node", sphereOffset[i]);
		sphereNodes[i]->attachObject(tempSpheres[i]);
		tempSpheres[i]->setVisible(false);
	}

	rndInt = (rand() % NUMSHAPES) + 1;
	if(rndInt > maxInt)
		maxInt = rndInt;

	sphereInt = rndInt;

	for(int i = 0; i < rndInt; i++)
	{
		bool visible = false;
		do
		{
			int rndPos = rand() % NUMSHAPES;

			if (tempSpheres[rndPos]->getVisible() == false)
			{
				tempSpheres[rndPos]->setVisible(true);
				visible = true;
				spheres[i] = tempSpheres[rndPos];
			}
		} while (visible == false);
	}
	
	// Get number of total shapes so far
	totalShapes += rndInt;

#pragma endregion Spheres
//-------------------------------------------------------------------------------------
#pragma region Tetra

	for(int i = 0; i < NUMSHAPES; i++)
	{
		tempTetrahedrons[i] = mSceneMgr->createEntity("Tetrahedron"+Ogre::StringConverter::toString(i+1), "HideAndSeekTetra.mesh");
		tempTetrahedrons[i]->setMaterialName("HideAndSeekShader/Tetra");
		tetraNodes[i] = mSceneMgr->getRootSceneNode()->createChildSceneNode("Tetra"+Ogre::StringConverter::toString(i+1)+"Node", tetraOffset[i]);
		tempTetrahedrons[i]->setVisible(false);
		tetraNodes[i]->attachObject(tempTetrahedrons[i]);
	}
	
	rndInt = (rand() % NUMSHAPES) + 1;
	if(rndInt > maxInt)
		maxInt = rndInt;

	tetraInt = rndInt;

	for(int i = 0; i < rndInt; i++)
	{
		bool visible = false;
		do
		{
			int rndPos = rand() % NUMSHAPES;

			if(tempTetrahedrons[rndPos]->getVisible() == false)
			{
				tempTetrahedrons[rndPos]->setVisible(true);
				visible = true;
				tetrahedrons[i] = tempTetrahedrons[rndPos]; 
			}
		} while (visible == false);
	}

	// Get number of total shapes so far
	totalShapes += rndInt;

#pragma endregion Tetra
//-------------------------------------------------------------------------------------
#pragma region Cylinder

	for(int i = 0; i < NUMSHAPES; i++)
	{
		tempTubes[i] = mSceneMgr->createEntity("Tube"+Ogre::StringConverter::toString(i+1), "HideAndSeekTube.mesh");
		tempTubes[i]->setMaterialName("HideAndSeekShader/Barrel");
		tubeNodes[i] = mSceneMgr->getRootSceneNode()->createChildSceneNode("Tube"+Ogre::StringConverter::toString(i+1), tubeOffset[i]);
		tempTubes[i]->setVisible(false);
		tubeNodes[i]->attachObject(tempTubes[i]);
	}

	rndInt = (rand() % NUMSHAPES) + 1;
	if(rndInt > maxInt)
		maxInt = rndInt;

	tubeInt = rndInt;

	for(int i = 0; i < rndInt; i++)
	{
		bool visible = false;
		do
		{
			int rndPos = rand() % NUMSHAPES;

			if(tempTubes[rndPos]->getVisible() == false)
			{
				tempTubes[rndPos]->setVisible(true);
				visible = true;
				tubes[i] = tempTubes[rndPos];
			}
		} while (visible == false);
	}
	
	// Get number of total shapes so far
	totalShapes += rndInt;

#pragma endregion Cylinder
//-------------------------------------------------------------------------------------
	
#pragma endregion Shapes

#pragma region CEGUI

	//Bootstrapping CEGUI
	mRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
//Setting Default Resources
	CEGUI::Imageset::setDefaultResourceGroup("Imagesets");
	CEGUI::Font::setDefaultResourceGroup("Fonts");
	CEGUI::Scheme::setDefaultResourceGroup("Schemes");
	CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel");
	CEGUI::WindowManager::setDefaultResourceGroup("Layouts");

//CEGUI skin
	CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");
//Set Default Mouse
//	CEGUI::System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
	
//Default gui window
	CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton();
	CEGUI::Window *sheet = wmgr.createWindow("DefaultWindow", "CEGUIDemo/Sheet");

//Creating button and setting size
	guiWnd = wmgr.createWindow("TaharezLook/Button", "CEGUIDemo/QuitButton");
	guiWnd->setText("Guesses = 10");
	guiWnd->setSize(CEGUI::UVector2(CEGUI::UDim(0.15, 0), CEGUI::UDim(0.05, 0)));
//Torch widget
	guiTorch = wmgr.createWindow("TaharezLook/Button", "CEGUIDemo/TorchButton");
	guiTorch->setText("Torch: Off");
	guiTorch->setSize(CEGUI::UVector2(CEGUI::UDim(0.15, 0), CEGUI::UDim(0.05, 0)));
	guiTorch->setPosition(CEGUI::UVector2(CEGUI::UDim(0.0, 0), CEGUI::UDim(0.055, 0)));
//End Widget
	guiEnd = wmgr.createWindow("TaharezLook/Button", "CEGUIDemo/EndButton");
	guiEnd->setText("End Game \n Press esc to exit");
	guiEnd->setSize(CEGUI::UVector2(CEGUI::UDim(0.3, 0), CEGUI::UDim(0.3, 0)));
	guiEnd->setPosition(CEGUI::UVector2(CEGUI::UDim(0.3, 0), CEGUI::UDim(0.3, 0)));
	guiEnd->setVisible(false);

//Attaching button to sheet
	sheet->addChildWindow(guiWnd);
	sheet->addChildWindow(guiTorch);
	sheet->addChildWindow(guiEnd);
	CEGUI::System::getSingleton().setGUISheet(sheet);

#pragma endregion CEGUI
}
//-------------------------------------------------------------------------------------
void GameApp::createFrameListener(void)
{
	BaseApplication::createFrameListener();

#pragma region CEGUI
	Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
    OIS::ParamList pl;
    size_t windowHnd = 0;
    std::ostringstream windowHndStr;

    mWindow->getCustomAttribute("WINDOW", &windowHnd);
    windowHndStr << windowHnd;
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

    mInputManager = OIS::InputManager::createInputSystem( pl );

    mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, true ));
    mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, true ));

    mMouse->setEventCallback(this);
    mKeyboard->setEventCallback(this);

    //Set initial mouse clipping size
    windowResized(mWindow);

    //Register as a Window listener
    Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

    mRoot->addFrameListener(this);
#pragma endregion CEGUI
	// Populate the camera container
	mCamNode = mCamera->getParentSceneNode();

	// set the rotation and move speed
	mRotate = 0.13;
	mMove = 250;
	
	mDirection = Ogre::Vector3::ZERO;
}
//-------------------------------------------------------------------------------------
bool GameApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	if(!processInput(evt))
		return false;
	if(mWindow->isClosed())
		return false;
	if(mShutDown)
		return false;

	mKeyboard->capture();
	mMouse->capture();
	mTrayMgr->frameRenderingQueued(evt);

	//mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);
	mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);

	CEGUI::System::getSingleton().injectTimePulse(evt.timeSinceLastFrame);
	
/*--------------- Collision ---------------*/

	pBox = player->getWorldBoundingBox();			// get players WORLD BB
	hiddenBox = hiddenShape->getWorldBoundingBox(); // get hidden WORLD BB

	// Iterate through ALL shapes AABB
	for(int i = 0; i < cubeInt; i++)
		cubeBox[i] = cubes[i]->getWorldBoundingBox();

	for(int i = 0; i < sphereInt; i++)
		sphereBox[i] = spheres[i]->getWorldBoundingBox();

	for(int i = 0; i < tetraInt; i++)
		tetraBox[i] = tetrahedrons[i]->getWorldBoundingBox();

	for(int i = 0; i < tubeInt; i++)
		tubeBox[i] = tubes[i]->getWorldBoundingBox();

	// Iterate through planes AABB
	for(int j = 0; j < NUMPLANES; j++)
		planeBox[j] = planes[j]->getWorldBoundingBox();

	// Iterate through platform AABB
	for(int k = 0; k < NUM_PLATS; k++)
		platBox[k] = platform[k]->getWorldBoundingBox();

	for(int k = 0; k < NUM_PLATS; k++)
		platCubeBox[k] = platCube[k]->getWorldBoundingBox();
	
	collision = false;
	// Check for collision between players AABB and the shapes AABB
	for(int m = 0; m < maxInt; m++)
		if(	CCollisionDetection::isColliding(pBox, cubeBox[m])||
			CCollisionDetection::isColliding(pBox, sphereBox[m])||
			CCollisionDetection::isColliding(pBox, tetraBox[m])||
			CCollisionDetection::isColliding(pBox, tubeBox[m]))
		{
			collision = true;
		}

	// Check for collision between players AABB and the floor
	for(int n = 0; n < NUMPLANES; n++)
		if(CCollisionDetection::isColliding(pBox, planeBox[n]))
			collision = true;
	
	// Check for collision between players AABB and the hidden Shape
	if(CCollisionDetection::isColliding(pBox, hiddenBox))
		collision = true;
	
	// Check for collision between players AABB and platform transporters
	for(int n = 0; n < NUM_PLATS; n++)
		if(CCollisionDetection::isColliding(pBox, platCubeBox[n]))
		{
			if(n >= 4 && n < 7)
				mCamNode->setPosition(0.0f, mCamNode->getPosition().y + 100.0f, 286.0f);
			if(n >= 7 && n < 10)
				mCamNode->setPosition(0.0f, mCamNode->getPosition().y - 100.0f, 286.0f);
		}

			

/*------------- End Collision -------------*/
    return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::processInput(const Ogre::FrameEvent& evt)
{
	static bool mMouseDown = false;
		
	// toggle current mouse state on Left Mouse Button click
	bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);

	// If LMB down and mMouseDown is true (!mMouseDown == true)
	if(currMouse && !mMouseDown)
	{
		// Get spotlight object
		// set invisible
		Ogre::Light* mTorch = mSceneMgr->getLight("Torch");
		mTorch->setVisible(!mTorch->isVisible());
	}

	// set mouse down to current mouse state for next frame
	mMouseDown = currMouse;
	
#pragma region Keyboard Controls
	Ogre::Vector3 newDir = Ogre::Vector3(0, 0, 1);
	Ogre::Vector3 yAxis = Ogre::Vector3(0, 1, 0);

	if(mKeyboard->isKeyDown(OIS::KC_W))
	{
		if(collision)
		{
			mDirection = mCamNode->getOrientation() * newDir * mMove;
			mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);
			//mDirection = (0,0,0);
		}
		else
			mDirection = mCamNode->getOrientation() * newDir * -mMove;
	}
	if(mKeyboard->isKeyDown(OIS::KC_S))
	{
		if(collision)
		{
			mDirection = mCamNode->getOrientation() * newDir * -mMove;
			mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);
			mDirection = (0,0,0);
		}
		else
			mDirection = mCamNode->getOrientation() * newDir * mMove;
	}
	if(mKeyboard->isKeyDown(OIS::KC_A))
	{
		if(collision)
		{
			mDirection = (mCamNode->getOrientation() * newDir).crossProduct(yAxis) * -mMove;
			mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);
			mDirection = (0,0,0);
		}
		else
			mDirection = (mCamNode->getOrientation() * newDir).crossProduct(yAxis) * mMove;
	}
	if(mKeyboard->isKeyDown(OIS::KC_D))
	{
		if(collision)
		{
			mDirection = (mCamNode->getOrientation() * newDir).crossProduct(yAxis) * mMove;
			mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);
			mDirection = (0,0,0);
		}
		else
			mDirection = (mCamNode->getOrientation() * newDir).crossProduct(yAxis) * -mMove;
	}
#pragma endregion Keyboard Controls


	return true;
}
//--------------------------------- OIS::KeyListener ----------------------------------
bool GameApp::keyPressed(const OIS::KeyEvent& evt)
{

	switch(evt.key)
    {
		case OIS::KC_ESCAPE: 
        mShutDown = true;
        break;

/*========= DEBUG ===========
		case OIS::KC_E:
			mDirection.y = -mMove;
			break;
 
		case OIS::KC_Q:
			mDirection.y = mMove;
			break;
============================*/
		case OIS::KC_G:
			active = !active;
			hiddenNode->showBoundingBox(active);
			break;

		default:
        break;
    }

	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::keyReleased(const OIS::KeyEvent& evt)
{
	switch (evt.key)
	{
	case OIS::KC_W:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_S:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_A:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_D:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_E:
		mDirection.y = 0;
		break;
 
	case OIS::KC_Q:
		mDirection.y = 0;
		break;

	default:
		break;
	}

	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::mouseMoved(const OIS::MouseEvent& evt)
{
	mCamNode->yaw(Ogre::Degree(-mRotate * evt.state.X.rel), Ogre::Node::TS_WORLD);

	CEGUI::System &sys = CEGUI::System::getSingleton();
	sys.injectMouseMove(evt.state.X.rel, evt.state.Y.rel);
// Scroll wheel.
	if (evt.state.Z.rel)
	{
		sys.injectMouseWheelChange(evt.state.Z.rel / 120.0f);
	}
	
	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::mousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	CEGUI::System::getSingleton().injectMouseButtonDown(convertButton(id));
	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::mouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	if(torch->isVisible())
	{
		guesses -= 1;
		guiWnd->setText("Guesses: " + Ogre::StringConverter::toString(guesses));
	}

	if(torch->isVisible())
	{
		guiTorch->setText("Torch: On");
	}

	if(!torch->isVisible())
	{
		guiTorch->setText("Torch: Off");
	}

	if(guesses <= 0)
	{
		guesses = 0;
		guiEnd->setVisible(true);
	}

	CEGUI::System::getSingleton().injectMouseButtonUp(convertButton(id));
	return true;
}
//-------------------------------------------------------------------------------------

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        GameApp app;

        try {
            app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occured: " <<
                e.getFullDescription().c_str() << std::endl;
#endif
        }

        return 0;
    }

#ifdef __cplusplus
}
#endif
